﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data.SqlClient;

namespace KLADR
{
    public partial class EnterKladr : UserControl
    {
        private AccessKladr accessKladr;
        private bool bDisableClearText = false;
        public string SqlConnectionString
        {
            get { return accessKladr.SqlConnectionString; }
            set 
            {
                if (string.IsNullOrEmpty(value)) return;
                accessKladr.SqlConnectionString = value;
            }
        }
        private string regionCode;
        private string districtCode;
        private string cityCode;
        private string townCode;
        private string streetCode;
       // private string houseCode;

        private bool isRegionCorrect;
        private bool isDistrictCorrect;
        private bool isCityCorrect;
        private bool isTownCorrect;
        private bool isStreetCorrect;

        public string KladrAddr
        {
            get
            {
                return GetAddressString();
            }
            set
            {
                if (string.IsNullOrEmpty(value)) return;
                ParseAddressString(value);
            }
        }

        public string KladrCode
        {
            get
            {
                StringBuilder result = new StringBuilder();
                if (string.IsNullOrEmpty(regionCode))
                    result.Append("00");
                else
                    result.Append(regionCode);
                if (string.IsNullOrEmpty(districtCode))
                    result.Append("000");
                else
                    result.Append(districtCode);
                if (string.IsNullOrEmpty(cityCode))
                    result.Append("000");
                else
                    result.Append(cityCode);
                if(string.IsNullOrEmpty(townCode))
                    result.Append("000");
                else
                    result.Append(townCode);
                return result.ToString();
            }
            set
            {
                string src = value as string;
                if (string.IsNullOrEmpty(src)) return;
                if (src.Length != 11) return;
                regionCode = src.Substring(0, 2);
                districtCode = src.Substring(2, 3);
                cityCode = src.Substring(5, 3);
                townCode = src.Substring(8, 3);
            }
        }

        private void FillTextBlocksByKladrCodeOrFields()
        {
            addressItem address;
            if (string.IsNullOrEmpty(regionCode) && string.IsNullOrEmpty(districtCode) && string.IsNullOrEmpty(townCode) && string.IsNullOrEmpty(cityCode))
            {
                if (string.IsNullOrEmpty(textBoxCity.Text) && string.IsNullOrEmpty(textBoxTown.Text))
                    return;
                bDisableClearText = true;
                textBoxRegion.Select();
                textBoxDistrict.Select();
                textBoxCity.Select();
                textBoxTown.Select();
                textBoxStreet.Select();
                textBoxHouse.Select();
                textBoxFlat.Select();
                bDisableClearText = false;
            }
            address = accessKladr.GetRegionByCodeAddress(regionCode);
            textBoxRegion.Text = address.name; textBoxRegionSocr.Text = address.socr;
            address = accessKladr.GetDistrictByCodeAddress(regionCode, districtCode);
            textBoxDistrict.Text = address.name; textBoxDistrictSocr.Text = address.socr;
            address = accessKladr.GetCityByCodeAddress(regionCode, districtCode, cityCode);
            textBoxCity.Text = address.name; textBoxCitySocr.Text = address.socr;
            address = accessKladr.GetTownByCodeAddress(regionCode, districtCode, townCode);
            textBoxTown.Text = address.name; textBoxTownSocr.Text = address.socr;
            if (string.IsNullOrEmpty(textBoxCity.Text) && string.IsNullOrEmpty(textBoxTown.Text)) return;
            textBoxStreet.Select();
        }

        public EnterKladr()
        {
            InitializeComponent();
            accessKladr = new AccessKladr();
            regionCode = "";
            districtCode = "";
            cityCode = "";
            townCode = "";
            streetCode = "";
            isRegionCorrect = true;
            isDistrictCorrect = true;
            isTownCorrect = true;
            isCityCorrect = true;
            isStreetCorrect = true;
        }

        private bool IsValidCharacters(string str)
        {
            bool result = true;
            if ((str.Contains(',') || str.Contains('_')))
                result = false;
            return result;
        }

        private string errText(object sender)
        {
            TextBox cur;
            cur = sender as TextBox;
            if (cur == null || IsValidCharacters(cur.Text)) return "";
            return "Символы \"запятая\" и \"нижнее подчеркивание\" не допустимы. ";
        }

        private void textBoxCorrectCharacters_Validated(object sender, EventArgs e)
        {
            TextBox cur;
            StringBuilder errString = new StringBuilder();
            if (sender is TextBox)
            {
                errString.Append(errText(sender));
            }

            cur = sender as TextBox;

            if ((sender as Control).Name == "textBoxRegion")
            {
                cur.Text = FindRegion(cur.Text, !bDisableClearText);
                isRegionCorrect = true;
                if (string.IsNullOrEmpty(regionCode))
                {
                    isRegionCorrect = false;
                    errString.Append("Регион не найден в классификаторе.");
                }
            }

            if ((sender as Control).Name == "textBoxDistrict")
            {
                isDistrictCorrect = true;
                if (!string.IsNullOrEmpty(cur.Text))
                {
                    cur.Text = FindDistrict(cur.Text, !bDisableClearText);
                    if (string.IsNullOrEmpty(districtCode))
                    {
                        isDistrictCorrect = false;
                        errString.Append("Район не найден в классификаторе.");
                    }
                }
            }

            if ((sender as Control).Name == "textBoxTown")
            {
                isTownCorrect = true;
                if (!string.IsNullOrEmpty(cur.Text))
                {
                    cur.Text = FindTown(cur.Text, !bDisableClearText);
                    if (string.IsNullOrEmpty(townCode))
                    {
                        isTownCorrect = false;
                        errString.Append("Населенный пункт не найден в классификаторе.");
                    }
                }
            }

            if ((sender as Control).Name == "textBoxCity")
            {
                isCityCorrect = true;
                if (!string.IsNullOrEmpty(cur.Text))
                {
                    cur.Text = FindCity(cur.Text, !bDisableClearText);
                    if (string.IsNullOrEmpty(cityCode))
                    {
                        isCityCorrect = false;
                        errString.Append("Город не найден в классификаторе.");
                    }
                }
            }

            if ((sender as Control).Name == "textBoxStreet")
            {
                isStreetCorrect = true;
                if (!string.IsNullOrEmpty(cur.Text))
                {
                    if (string.IsNullOrEmpty(textBoxStreetSocr.Text))
                        cur.Text = FindStreet(cur.Text, !bDisableClearText);
                    else
                        cur.Text = FindStreet(cur.Text, textBoxStreetSocr.Text.Trim().ToUpper(), !bDisableClearText);
                    if (string.IsNullOrEmpty(streetCode))
                    {
                        isStreetCorrect = false;
                        errString.Append("Улица не найдена в классификаторе.");
                    }
                }
            }

            errorProviderValidCharacters.SetError(sender as Control, errString.ToString());
        }

        private string ConvertHouseNumber(string house)
        {
            return house;
        }
        private string ParseHouseNumber(string houseKladr)
        {
            return DropSpaces(houseKladr);
        }

        private string DropCommasUnderline(string src)
        {
            StringBuilder result = new StringBuilder();
            char[] srclist = src.ToCharArray();
            foreach (char item in srclist)
            {
                if (item == ',' || item=='_') continue;
                result.Append(item);
            }
            return result.ToString();
        }

        private bool IsAddressEmpty(string src)
        {
            string newString = DropSpaces(DropCommasUnderline(src)).Trim();
            return string.IsNullOrEmpty(newString);
        }

        private string GetAddressString()
        {
            StringBuilder str = new StringBuilder();
            string result;
            str.Append(string.Format("{0} {1}", DropCommasUnderline(textBoxRegion.Text.Trim().ToUpper()), DropCommasUnderline(textBoxRegionSocr.Text.Trim().ToUpper())).Trim()).Append(",");
            str.Append(string.Format("{0} {1}", DropCommasUnderline(textBoxDistrict.Text.Trim().ToUpper()), DropCommasUnderline(textBoxDistrictSocr.Text.Trim().ToUpper())).Trim()).Append(",");
            str.Append(string.Format("{0} {1}", DropCommasUnderline(textBoxCity.Text.Trim().ToUpper()), DropCommasUnderline(textBoxCitySocr.Text.Trim().ToUpper())).Trim()).Append(",");
            str.Append(string.Format("{0} {1}", DropCommasUnderline(textBoxTown.Text.Trim().ToUpper()), DropCommasUnderline(textBoxTownSocr.Text.Trim().ToUpper())).Trim()).Append(",");
            str.Append(string.Format("{0} {1}", DropCommasUnderline(textBoxStreet.Text.Trim().ToUpper()), DropCommasUnderline(textBoxStreetSocr.Text.Trim().ToUpper())).Trim()).Append(",");
            str.Append(ConvertHouseNumber(textBoxHouse.Text.Trim().ToUpper())).Append(",");
            str.Append(textBoxFlat.Text.Trim().ToUpper());
            result = str.ToString();
            if (IsAddressEmpty(result)) return "";
            return result;
        }

        /// <summary>
        /// Получить последнее слово в строке
        /// </summary>
        /// <param name="src">строка</param>
        /// <returns>последнее слово в строке</returns>
        private string GetLastWord(string src)
        {
            int len = src.Length;
            src = src.Trim();
            int pos = src.LastIndexOf(' ');
            if (pos == -1) return ""; 
            return src.Substring(pos+1, len - pos-1);
        }

        /// <summary>
        /// Отбросить последнее слово в строке
        /// </summary>
        /// <param name="src">строка</param>
        /// <returns>строка, без последнего слова</returns>
        private string DropLastWord(string src)
        {
            src = src.Trim();
            int pos = src.LastIndexOf(' ');
            if (pos == -1) return src;
            return src.Substring(0, pos);
        }

        /// <summary>
        /// Удалить из строки все пробелы
        /// </summary>
        /// <param name="src"></param>
        /// <returns></returns>
        private string DropSpaces(string src)
        {
            StringBuilder result = new StringBuilder();
            char[] srclist = src.ToCharArray();
            foreach (char item in srclist)
            {
                if (item == ' ') continue;
                result.Append(item);
            }
            return result.ToString();
        }

        private void ParseAddressString(string address)
        {
            string[] list = address.Split(new char[] { ',' });
            ClearRegion();
            int list_cnt = list.Count();
            if (list_cnt > 0)
            {
                textBoxRegion.Text = DropLastWord(list[0]); 
            }
            if (list_cnt > 1)
            {
                textBoxDistrict.Text = DropLastWord(list[1]);
            }
            if (list_cnt > 2)
            {
                textBoxCity.Text = DropLastWord(list[2]);
            }
            if (list_cnt > 3)
            {
                textBoxTown.Text = DropLastWord(list[3]);
            }
            if (list_cnt > 4)
            {
                textBoxStreet.Text = DropLastWord(list[4]);
                textBoxStreetSocr.Text = GetLastWord(list[4]);
            }
            if (list_cnt > 5)
            {
                textBoxHouse.Text = ParseHouseNumber(list[5]);
            }
            if (list_cnt > 6)
            {
                textBoxFlat.Text = list[6];
            }
        }

        private bool checkValidState()
        {
            return isRegionCorrect && isDistrictCorrect && isTownCorrect && isCityCorrect && isStreetCorrect;
        }

        private void buttonSelectRegion_Click(object sender, EventArgs e)
        {
            textBoxRegion.Text = FindRegion("");
        }

        private void buttonSelectDistrict_Click(object sender, EventArgs e)
        {
            textBoxDistrict.Text = FindDistrict("");
        }

        private void buttonSelectCity_Click(object sender, EventArgs e)
        {
            textBoxCity.Text = FindCity("");
        }

        private void buttonSelectTown_Click(object sender, EventArgs e)
        {
            textBoxTown.Text = FindTown("");
        }

        private void buttonSelectStreet_Click(object sender, EventArgs e)
        {
            textBoxStreet.Text = FindStreet("");
        }

        private void buttonSelectHouse_Click(object sender, EventArgs e)
        {

        }

        /// <summary>
        /// Вспомогательная процедура выбора элемента улицы из списка
        /// </summary>
        /// <param name="ds"></param>
        /// <param name="Caption"></param>
        /// <param name="streetItemCode"></param>
        /// <param name="startPos"></param>
        /// <param name="Length"></param>
        /// <param name="textBoxStreetSocr"></param>
        /// <returns></returns>
        private string SelectStreetElement(kladrDataSet ds, string Caption, out string streetItemCode, int startPos, int Length, TextBox textBoxStreetSocr)
        {
            string result = "";
            streetItemCode = "";
            {
                FormSelectStreet frmRegion = new FormSelectStreet();
                frmRegion.SetText = Caption;
                frmRegion.DataSource = ds;
                if (ds.street.Rows.Count == 0)
                {
                    MessageBox.Show("Элементов в классификаторе не найдено.");
                    return result;
                }
                if (frmRegion.ShowDialog() == DialogResult.OK)
                {
                    if (frmRegion.IsChanged == true)
                    {
                        textBoxStreetSocr.Text = "";
                        return frmRegion.StreetName;
                    }
                    else
                    {
                        streetItemCode = frmRegion.StreetCode.Substring(startPos, Length);
                        result = frmRegion.StreetName;
                        textBoxStreetSocr.Text = frmRegion.StreetSocr;
                    }
                }

            }
            return result;
        }
        /// <summary>
        /// Вспомогательная процедура выбора элемента кладр из списка
        /// </summary>
        /// <param name="ds"></param>
        /// <param name="Caption"></param>
        /// <param name="kladrItemCode"></param>
        /// <param name="startPos"></param>
        /// <param name="Length"></param>
        /// <param name="textBoxKladrSocr"></param>
        /// <returns></returns>
        private string SelectKladrElement(kladrDataSet ds, string Caption, out string kladrItemCode, int startPos, int Length, TextBox textBoxKladrSocr)
        {
            string result = "";
            kladrItemCode = "";
            try
            {
                FormSelectKladr frmRegion = new FormSelectKladr();
                frmRegion.SetText = Caption;
                frmRegion.DataSource = ds;
                if (ds.kladr.Rows.Count == 0)
                {
                    MessageBox.Show("Элементов в классификаторе не найдено.");
                    return result;
                }
                if (frmRegion.ShowDialog() == DialogResult.OK)
                {
                    if (frmRegion.IsChanged == true)
                    {
                        textBoxKladrSocr.Text = "";
                        return frmRegion.KladrName;
                    }
                    else
                    {
                        kladrItemCode = frmRegion.KladrCode.Substring(startPos, Length);
                        result = frmRegion.KladrName;
                        textBoxKladrSocr.Text = frmRegion.KladrSocr;
                    }
                }

            }
            catch (Exception)
            {
            }
            return result;
        }


        private string FindRegion(string regionName)
        {
            return FindRegion(regionName, true);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="regionName"></param>
        /// <param name="recursy"></param>
        /// <returns></returns>
        private string FindRegion(string regionName, bool EnableForm)
        {
            string old = regionName;
            addressItem address;
            string result = regionName;
            ClearRegion();
            address = accessKladr.FindRegionAddress(regionName);
            if (!string.IsNullOrEmpty(address.code))
            {
                result = address.name;
                textBoxRegionSocr.Text = address.socr;
                regionCode = address.code.Substring(0, 2);
                return result;
            }
            if (EnableForm == false) return result;
            result = SelectKladrElement(address.ds, "Выбор региона.", out regionCode, 0, 2, textBoxRegionSocr);
            if (string.IsNullOrEmpty(result)) result = old;
            return result;
        }

        private void ClearRegion()
        {
            ClearDistrict();
            regionCode = "";
            if (bDisableClearText) return;
            textBoxRegionSocr.Text = "";
            textBoxRegion.Text = "";
        }

        private void ClearDistrict()
        {
            ClearTown();
            ClearCity();
            districtCode = "";
            if (bDisableClearText) return;
            textBoxDistrictSocr.Text = "";
            textBoxDistrict.Text = "";
        }

        private void ClearCity()
        {
            ClearStreet();
            cityCode = "";
            if (bDisableClearText) return;
            textBoxCitySocr.Text = "";
            textBoxCity.Text = "";
        }

        private void ClearStreet()
        {
            ClearHouse();
            streetCode = "";
            if (bDisableClearText) return;
            textBoxStreet.Text = "";
            textBoxStreetSocr.Text = "";
        }

        private void ClearHouse()
        {
            ClearFlat();
            if (bDisableClearText) return;
            textBoxHouse.Text = "";
        }

        private void ClearFlat()
        {
            if (bDisableClearText) return;
            textBoxFlat.Text = "";
        }

        private void ClearTown()
        {
            townCode = "";
            ClearStreet();
            if (bDisableClearText) return;
            textBoxTownSocr.Text = "";
            textBoxTown.Text = "";
        }

        private string FindDistrict(string districtName)
        {
            return FindDistrict(districtName, true);
        }

        private string FindDistrict(string districtName, bool EnableForm)
        {
            string old = districtName;
            addressItem address;
            string result = districtName;
            ClearDistrict();
            if (string.IsNullOrEmpty(regionCode)) return result;
            address = accessKladr.FindDistrictAddress(regionCode, districtName);
            if (!string.IsNullOrEmpty(address.code))
            {
                result = address.name;
                textBoxDistrictSocr.Text = address.socr;
                districtCode = address.code.Substring(2, 3);
                return result;
            }
            if (EnableForm == false) return result;
            result = SelectKladrElement(address.ds, "Выбор района.", out districtCode, 2, 3, textBoxDistrictSocr);
            if (string.IsNullOrEmpty(result)) result = old;
            return result;
        }
        private string FindTown(string townName)
        {
            return FindTown(townName, true);
        }

        private string FindTown(string townName, bool EnableForm)
        {
            string old = townName;
            addressItem address;
            string result = townName;
            string disCode = districtCode;
            ClearTown();
            ClearCity();
            if (string.IsNullOrEmpty(regionCode)) return result;
            if (string.IsNullOrEmpty(disCode))
                disCode = "000";
            address = accessKladr.FindTownAddress(regionCode, disCode, townName);
            if (!string.IsNullOrEmpty(address.code))
            {
                result = address.name;
                textBoxDistrictSocr.Text = address.socr;
                townCode = address.code.Substring(8, 3);
                return result;
            }
            if (EnableForm == false) return result;
            result = SelectKladrElement(address.ds, "Выбор населенного пункта.", out townCode, 8, 3, textBoxTownSocr);
            if (string.IsNullOrEmpty(result)) result = old;
            return result;
        }

        private string FindCity(string cityName)
        {
            return FindCity(cityName, true);
        }

        private string FindCity(string cityName, bool EnableForm)
        {
            string old = cityName;
            addressItem address;
            string result = cityName;
            string disCode = districtCode;
            ClearTown();
            ClearCity();
            if (string.IsNullOrEmpty(regionCode)) return result;
            if (string.IsNullOrEmpty(disCode))
                disCode = "000";
            address = accessKladr.FindCityAddress(regionCode, disCode, cityName);
            if (!string.IsNullOrEmpty(address.code))
            {
                result = address.name;
                textBoxCitySocr.Text = address.socr;
                cityCode = address.code.Substring(5, 3);
                return result;
            }
            if (EnableForm == false) return result;
            result = SelectKladrElement(address.ds, "Выбор города.", out cityCode, 5, 3, textBoxCitySocr);
            if (string.IsNullOrEmpty(result)) result = old;
            return result;
        }


        private void EnterKladr_Load(object sender, EventArgs e)
        {
            FillTextBlocksByKladrCodeOrFields();
        }

        private string FindStreet(string streetName, string socr)
        {
            return FindStreet(streetName, socr, true);
        }

        private string FindStreet(string streetName, string socr, bool EnableForm)
        {
            string old = streetName;
            addressItem address;
            string result = streetName;
            streetCode = "";
            if (string.IsNullOrEmpty(KladrCode))
            {
                MessageBox.Show("Нельзя выбрать улицу вне населенного пункта.");
                textBoxStreetSocr.Text = "";
                return "";
            }
            address = accessKladr.FindStreetAddress(KladrCode, streetName, socr);
            if (!string.IsNullOrEmpty(address.code))
            {
                result = address.name;
                textBoxStreetSocr.Text = address.socr;
                streetCode = address.code.Substring(5, 3);
                return result;
            }
            if (EnableForm == false) return result;
            result = SelectStreetElement(address.ds, "Выбор улицы.", out streetCode, 11, 4, textBoxStreetSocr);
            if (string.IsNullOrEmpty(result)) result = old;
            return result;
        }


        private string FindStreet(string streetName)
        {
            return FindStreet(streetName, true);
        }

        private string FindStreet(string streetName, bool EnableForm)
        {
            string old = streetName;
            addressItem address;
            string result = streetName;
            streetCode = "";
            if (string.IsNullOrEmpty(KladrCode))
            {
                MessageBox.Show("Нельзя выбрать улицу вне населенного пункта.");
                textBoxStreetSocr.Text = "";
                return "";
            }
            address = accessKladr.FindStreetAddress(KladrCode, streetName);
            if (!string.IsNullOrEmpty(address.code))
            {
                result = address.name;
                textBoxStreetSocr.Text = address.socr;
                streetCode = address.code.Substring(5, 3);
                return result;
            }
            if (EnableForm == false) return result;
            result = SelectStreetElement(address.ds, "Выбор улицы.", out streetCode, 11, 4, textBoxStreetSocr);
            if (string.IsNullOrEmpty(result)) result = old;
            return result;
        }

        private void buttonClearRegion_Click(object sender, EventArgs e)
        {
            ClearRegion();
        }

        private void buttonClearDistrict_Click(object sender, EventArgs e)
        {
            ClearDistrict();
        }

        private void buttonClearCity_Click(object sender, EventArgs e)
        {
            ClearCity();
        }

        private void buttonClearTown_Click(object sender, EventArgs e)
        {
            ClearTown();
        }

        private void buttonClearStreet_Click(object sender, EventArgs e)
        {
            ClearStreet();
        }

        private void buttonClearHouse_Click(object sender, EventArgs e)
        {
            ClearHouse();
        }

        private void buttonClearFlat_Click(object sender, EventArgs e)
        {
            ClearFlat();
        }
    }
}
